package com.zhentao.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhentao.annotation.OperationLog;
import com.zhentao.pojo.CustomsDataLog;
import com.zhentao.service.CustomsDataLogService;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

/**
 * 操作日志切面
 * 自动记录标注了@OperationLog注解的方法调用日志
 */
@Aspect
@Component
public class OperationLogAspect {

    @Autowired
    private CustomsDataLogService customsDataLogService;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 定义切点：所有标注了@OperationLog注解的方法
     */
    @Pointcut("@annotation(com.zhentao.annotation.OperationLog)")
    public void operationLogPointcut() {
    }

    /**
     * 环绕通知：记录操作日志
     */
    @Around("operationLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        Exception exception = null;

        try {
            // 执行目标方法
            result = joinPoint.proceed();
            return result;
        } catch (Exception e) {
            exception = e;
            throw e;
        } finally {
            // 记录操作日志
            recordOperationLog(joinPoint, result, exception, System.currentTimeMillis() - startTime);
        }
    }

    /**
     * 记录操作日志
     */
    private void recordOperationLog(ProceedingJoinPoint joinPoint, Object result, Exception exception, long executionTime) {
        try {
            // 获取方法签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            
            // 获取注解信息
            OperationLog operationLog = method.getAnnotation(OperationLog.class);
            if (operationLog == null) {
                return;
            }

            // 获取请求信息
            HttpServletRequest request = getHttpServletRequest();
            
            // 创建日志对象
            CustomsDataLog log = new CustomsDataLog();
            log.setBizModule(operationLog.bizModule());
            log.setBizType(operationLog.bizType());
            log.setOperationDesc(operationLog.description());
            log.setOperateTime(new Date());
            
            // 设置关联ID
            String relationId = generateRelationId(joinPoint, result);
            log.setRelationId(relationId);
            
            // 设置操作人
            String operator = getOperatorFromRequest(request, joinPoint);
            log.setOperator(operator);
            
            // 记录请求参数
            if (operationLog.recordParams()) {
                String requestParams = getRequestParams(joinPoint, request);
                log.setRequestParams(requestParams);
            }
            
            // 记录响应结果
            if (operationLog.recordResult()) {
                String responseResult = getResponseResult(result, exception, executionTime);
                log.setResponseResult(responseResult);
            }
            
            // 设置扩展信息
            String extInfo = getExtInfo(request, method, executionTime);
            log.setExtInfo(extInfo);
            
            // 异步保存日志（避免影响主业务）
            saveLogAsync(log);
            
        } catch (Exception e) {
            // 日志记录失败不应影响主业务
            e.printStackTrace();
        }
    }

    /**
     * 获取HTTP请求对象
     */
    private HttpServletRequest getHttpServletRequest() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            return attributes != null ? attributes.getRequest() : null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 生成关联ID
     */
    private String generateRelationId(ProceedingJoinPoint joinPoint, Object result) {
        try {
            // 尝试从结果中提取ID
            if (result instanceof Map) {
                Map<String, Object> resultMap = (Map<String, Object>) result;
                Object data = resultMap.get("data");
                if (data instanceof Map) {
                    Object id = ((Map<String, Object>) data).get("id");
                    if (id != null) {
                        return id.toString();
                    }
                }
            }
            
            // 使用时间戳作为默认关联ID
            return "LOG_" + System.currentTimeMillis();
        } catch (Exception e) {
            return "LOG_" + System.currentTimeMillis();
        }
    }

    /**
     * 从请求中获取操作人信息
     */
    private String getOperatorFromRequest(HttpServletRequest request, ProceedingJoinPoint joinPoint) {
        try {
            // 优先从请求头获取用户ID
            if (request != null) {
                String userId = request.getHeader("userId");
                if (userId != null && !userId.isEmpty()) {
                    return userId;
                }
                
                // 从请求参数获取
                userId = request.getParameter("userId");
                if (userId != null && !userId.isEmpty()) {
                    return userId;
                }
            }
            
            // 从方法参数中获取userId
            Object[] args = joinPoint.getArgs();
            String[] paramNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
            
            for (int i = 0; i < paramNames.length; i++) {
                if ("userId".equals(paramNames[i]) && args[i] != null) {
                    return args[i].toString();
                }
                
                // 如果参数是Map，尝试从中获取userId
                if (args[i] instanceof Map) {
                    Map<String, Object> paramMap = (Map<String, Object>) args[i];
                    Object userId = paramMap.get("userId");
                    if (userId != null) {
                        return userId.toString();
                    }
                }
            }
            
            return "SYSTEM";
        } catch (Exception e) {
            return "UNKNOWN";
        }
    }

    /**
     * 获取请求参数
     */
    private String getRequestParams(ProceedingJoinPoint joinPoint, HttpServletRequest request) {
        try {
            Object[] args = joinPoint.getArgs();
            String[] paramNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
            
            StringBuilder params = new StringBuilder();
            
            // 添加URL参数
            if (request != null) {
                String queryString = request.getQueryString();
                if (queryString != null && !queryString.isEmpty()) {
                    params.append("URL参数: ").append(queryString).append("; ");
                }
            }
            
            // 添加方法参数
            for (int i = 0; i < args.length; i++) {
                if (args[i] != null) {
                    params.append(paramNames[i]).append("=");
                    
                    // 对于复杂对象，转换为JSON
                    if (isSimpleType(args[i])) {
                        params.append(args[i].toString());
                    } else {
                        try {
                            params.append(objectMapper.writeValueAsString(args[i]));
                        } catch (Exception e) {
                            params.append(args[i].getClass().getSimpleName());
                        }
                    }
                    params.append("; ");
                }
            }
            
            return params.length() > 0 ? params.substring(0, params.length() - 2) : "";
        } catch (Exception e) {
            return "参数解析失败: " + e.getMessage();
        }
    }

    /**
     * 获取响应结果
     */
    private String getResponseResult(Object result, Exception exception, long executionTime) {
        try {
            if (exception != null) {
                return "执行失败: " + exception.getMessage() + ", 耗时: " + executionTime + "ms";
            }
            
            if (result instanceof Map) {
                Map<String, Object> resultMap = (Map<String, Object>) result;
                Object code = resultMap.get("code");
                Object message = resultMap.get("message");
                
                return "执行结果: code=" + code + ", message=" + message + ", 耗时: " + executionTime + "ms";
            }
            
            return "执行成功, 耗时: " + executionTime + "ms";
        } catch (Exception e) {
            return "结果解析失败, 耗时: " + executionTime + "ms";
        }
    }

    /**
     * 获取扩展信息
     */
    private String getExtInfo(HttpServletRequest request, Method method, long executionTime) {
        try {
            StringBuilder extInfo = new StringBuilder();
            
            if (request != null) {
                extInfo.append("IP: ").append(getClientIpAddress(request)).append("; ");
                extInfo.append("UserAgent: ").append(request.getHeader("User-Agent")).append("; ");
            }
            
            extInfo.append("方法: ").append(method.getDeclaringClass().getSimpleName())
                   .append(".").append(method.getName()).append("; ");
            extInfo.append("执行时间: ").append(executionTime).append("ms");
            
            return extInfo.toString();
        } catch (Exception e) {
            return "扩展信息获取失败";
        }
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 判断是否为简单类型
     */
    private boolean isSimpleType(Object obj) {
        return obj instanceof String || obj instanceof Number || 
               obj instanceof Boolean || obj instanceof Character;
    }

    /**
     * 异步保存日志
     */
    private void saveLogAsync(CustomsDataLog log) {
        try {
            // 这里可以使用线程池异步保存，避免影响主业务性能
            customsDataLogService.save(log);
        } catch (Exception e) {
            // 日志保存失败，记录到系统日志
            System.err.println("操作日志保存失败: " + e.getMessage());
        }
    }
}
